package beautify

import (
	"bytes"
	"errors"
	"fmt"
	"gitee.com/hongzhaomin/hzm-common-go/strutil"
	"gitee.com/hongzhaomin/hzm-common-go/strutil/color"
	"gitee.com/hongzhaomin/hzm-common-go/toolkit"
	"reflect"
	"sync"
	"time"
)

// TabFormatter 表格格式化配置
type TabFormatter struct {
	LeftMargin        int                                     // 左边距设置
	Padding           int                                     // 内边距设置
	Vertex            string                                  // 设置表格中各个顶点的字符串
	TitleTopBorder    byte                                    // 设置表格中表头顶部边框字符
	TitleBottomBorder byte                                    // 设置表格中表头底部边框字符
	DataBorder        byte                                    // 设置表格中数据边框字符
	DataSegment       string                                  // 设置表格中数据分隔符字符串
	GlobalColor       color.Color                             // 全局颜色设置
	TitleColorFun     func(title string) color.Color          // 表头颜色设置
	CellColorFun      func(title, cellVal string) color.Color // 表数据颜色设置
}

// TableFmt 表格格式化输出对象
type TableFmt struct {
	formatter        *TabFormatter    // 表格格式化配置
	tabFormatterName TabFormatterType // 表格格式化配置名称
	buf              *bytes.Buffer    // 字符串拼接工具
	mu               *sync.Mutex      // 锁
	titles           []string         // 表头
	data             [][]string       // 表数据
	cellWidths       []int            // 单元格宽度数据
}

func NewTableFmt() *TableFmt {
	formatter := name2TabFormatterMap[Gird]
	tf := &TableFmt{
		formatter:        &formatter,
		tabFormatterName: Gird,
		buf:              new(bytes.Buffer),
		mu:               new(sync.Mutex),
	}
	return tf
}

// SetTabFormatter 设置表格格式化配置
func (my *TableFmt) SetTabFormatter(tabFormatterType TabFormatterType) *TableFmt {
	formatter, ok := name2TabFormatterMap[tabFormatterType]
	if !ok {
		panic(errors.New("表格格式化配置不存在"))
	}
	my.formatter = &formatter
	my.tabFormatterName = tabFormatterType
	return my
}

// CustomizeTabFormatter 自定义表格格式化配置
func (my *TableFmt) CustomizeTabFormatter(formatter TabFormatter) *TableFmt {
	my.formatter = &formatter
	my.tabFormatterName = ""
	return my
}

func (my *TableFmt) Println(titles []string, data any) {
	fmt.Println(my.Format(titles, data))
}

func (my *TableFmt) Println4Struct(obj any) {
	fmt.Println(my.FormatStruct(obj))
}

// FormatStruct 根据数据传入的结构体类型，自动解析表头并格式化数据输出
func (my *TableFmt) FormatStruct(obj any) string {
	if obj == nil {
		return ""
	}

	rv := reflect.Indirect(reflect.ValueOf(obj))
	rt := reflect.TypeOf(obj)
	if rt.Kind() == reflect.Ptr {
		rt = rt.Elem()
	}
	var rowsListLen int
	switch rt.Kind() {
	case reflect.Slice, reflect.Array:
		rowsListLen = rv.Len()
		if rowsListLen == 0 {
			return ""
		}
		titles, title2FieldNameMap := parseStruct(rt.Elem())
		rowsList := make([][]string, rowsListLen)
		for i := 0; i < rowsListLen; i++ {
			rvEle := reflect.Indirect(rv.Index(i))
			rowsList[i] = struct2Rows(rvEle, titles, title2FieldNameMap)
		}
		return my.format(titles, rowsList)
	case reflect.Struct:
		titles, title2FieldNameMap := parseStruct(rt)
		return my.format(titles, [][]string{struct2Rows(rv, titles, title2FieldNameMap)})
	default:
		panic(errors.New("不支持的类型"))
	}
}

func (my *TableFmt) Format(titles []string, data any) string {
	if len(titles) == 0 {
		return ""
	}

	if data == nil {
		return ""
	}

	switch v := data.(type) {
	case [][]string:
		return my.format(titles, v)
	case [][]int32:
		return my.format(titles, toStrArrs(v))
	case [][]int64:
		return my.format(titles, toStrArrs(v))
	case [][]int:
		return my.format(titles, toStrArrs(v))
	case [][]bool:
		return my.format(titles, toStrArrs(v))
	case [][]float64:
		return my.format(titles, toStrArrs(v))
	case [][]any:
		return my.format(titles, toStrArrs(v))
	case []string:
		return my.format(titles, [][]string{v})
	case []any:
		return my.format(titles, toStrArrs([][]any{v}))
	default:
		panic(errors.New("不支持的数据类型"))
	}
}

func (my *TableFmt) format(titles []string, data [][]string) string {
	if len(titles) == 0 {
		return ""
	}

	if len(data) == 0 {
		return ""
	}

	my.mu.Lock()
	defer my.mu.Unlock()
	my.titles = titles
	my.data = data
	my.prepare()

	return my.formatter.GlobalColor.Parse(my.doFormat())
}

func (my *TableFmt) doFormat() string {
	formatter := my.formatter
	lines := make([]string, 0, len(my.data)*2+3)
	// 表头顶部边框
	if formatter.TitleTopBorder != 0 {
		lines = append(lines, my.borderLine(string(formatter.TitleTopBorder)))
	}
	// 表头行
	lines = append(lines, my.dataLine(my.titles, formatter.DataSegment, true))
	// 表头底部边框
	if formatter.TitleBottomBorder != 0 {
		lines = append(lines, my.borderLine(string(formatter.TitleBottomBorder)))
	}

	// 遍历所有数据
	for _, row := range my.data {
		// 数据行
		lines = append(lines, my.dataLine(row, formatter.DataSegment, false))
		// 数据边框
		if formatter.DataBorder != 0 {
			lines = append(lines, my.borderLine(string(formatter.DataBorder)))
		}
	}

	for _, line := range lines {
		my.buf.WriteString(line)
		my.buf.WriteString("\n")
	}
	tableStr := my.buf.String()

	my.buf.Reset()
	return tableStr
}

func (my *TableFmt) prepare() {
	formatter := my.formatter
	cellWidths := make([]int, len(my.titles))
	for i, title := range my.titles {
		cellWidths[i] = my.strCount(title) + formatter.Padding*2
	}

	for _, arr := range my.data {
		for i, s := range arr {
			dataCw := my.strCount(s)
			cw := cellWidths[i]
			if dataCw > cw {
				cellWidths[i] = dataCw + formatter.Padding*2
			}
		}
	}
	my.cellWidths = cellWidths

	if _, ok := name2TabFormatterMap[my.tabFormatterName]; !ok {
		// 不存在表示需要校验分隔符和顶点符号长度是否一致，不一致则改成一致，否则影响表格美观
		formatter.Vertex = my.buildVertexOrSegment(formatter.Vertex)
		formatter.DataSegment = my.buildVertexOrSegment(formatter.DataSegment)
	}
}

func (my *TableFmt) borderLine(border string) string {
	for i := 0; i < my.formatter.LeftMargin; i++ {
		my.buf.WriteString(" ")
	}

	my.buf.WriteString(my.formatter.Vertex) // 表格顶角字符
	for _, width := range my.cellWidths {
		for i := 0; i < width; i++ {
			my.buf.WriteString(border)
		}
		my.buf.WriteString(my.formatter.Vertex)
	}
	str := my.buf.String()

	// 用完归零
	my.buf.Reset()

	return str
}

func (my *TableFmt) dataLine(row []string, segment string, isTitle bool) string {
	formatter := my.formatter
	for i := 0; i < formatter.LeftMargin; i++ {
		my.buf.WriteString(" ")
	}

	removeBorder := formatter.TitleTopBorder == 0 && formatter.TitleBottomBorder == 0 && formatter.DataBorder == 0
	if !removeBorder {
		my.buf.WriteString(segment)
	}

	for i, cell := range row {
		my.buf.WriteString(my.buildCell(i, cell, isTitle))
		if i == len(row)-1 && removeBorder {
			break
		}
		my.buf.WriteString(segment)
	}

	str := my.buf.String()

	// 用完归零
	my.buf.Reset()

	return str
}

func (my *TableFmt) buildCell(index int, cellVal string, isTitle bool) string {
	buffer := new(bytes.Buffer)
	cw := my.cellWidths[index]
	contentLen := my.strCount(cellVal)

	// 数据前缩进
	frontLen := (cw - contentLen) / 2
	for i := 0; i < frontLen; i++ {
		buffer.WriteString(" ")
	}

	// 数据
	buffer.Write([]byte(cellVal))

	// 数据后缩进
	for i := 0; i < cw-contentLen-frontLen; i++ {
		buffer.WriteString(" ")
	}
	cell := buffer.String()

	// 处理配置的颜色
	formatter := my.formatter
	globalColor := formatter.GlobalColor
	if isTitle {
		// 处理表头颜色
		if formatter.TitleColorFun != nil {
			cell = formatter.TitleColorFun(cellVal).Parse(cell)
			if globalColor.Valid() {
				cell = color.Reset.String() + cell + globalColor.String()
			}
		}
	} else {
		// 处理数据颜色
		if formatter.CellColorFun != nil {
			cell = formatter.CellColorFun(my.titles[index], cellVal).Parse(cell)
			if globalColor.Valid() {
				cell = color.Reset.String() + cell + globalColor.String()
			}
		}
	}
	return cell
}

func (my *TableFmt) buildVertexOrSegment(vertexOrSegment string) string {
	formatter := my.formatter
	buffer := new(bytes.Buffer)
	width := toolkit.Max(my.strCount(formatter.Vertex), my.strCount(formatter.DataSegment))
	contentLen := my.strCount(vertexOrSegment)

	// 数据前缩进
	frontLen := (width - contentLen) / 2
	for i := 0; i < frontLen; i++ {
		buffer.WriteString(" ")
	}

	// 数据
	buffer.Write([]byte(vertexOrSegment))

	// 数据后缩进
	for i := 0; i < width-contentLen-frontLen; i++ {
		buffer.WriteString(" ")
	}
	return buffer.String()
}

func (my *TableFmt) strCount(str string) int {
	cnt := 0
	for _, r := range []rune(str) {
		if strutil.IsChinese(r) {
			// 一个汉字占两个字符（注意不是字节）
			cnt += 2
		} else {
			cnt++
		}
	}
	return cnt
}

func toStrArrs[T any](v [][]T) [][]string {
	arrs := make([][]string, len(v))
	for i, eles := range v {
		arr := make([]string, len(eles))
		for j, ele := range eles {
			arr[j] = convertStr(ele)
		}
		arrs[i] = arr
	}
	return arrs
}

func convertStr(v any) string {
	eleStr, err := toolkit.ConvertStr4Any(v)
	if err != nil {
		switch anyEle := v.(type) {
		case time.Time:
			eleStr = anyEle.Format(time.DateTime)
		case *time.Time:
			eleStr = anyEle.Format(time.DateTime)
		default:
			panic(err)
		}
	}
	return eleStr
}

func struct2Rows(rv reflect.Value, titles []string, title2FieldNameMap map[string]string) []string {
	rows := make([]string, len(titles))
	for j, title := range titles {
		fieldName := title2FieldNameMap[title]
		rvField := rv.FieldByName(fieldName)
		rows[j] = convertStr(rvField.Interface())
	}
	return rows
}

func parseStruct(rt reflect.Type) ([]string, map[string]string) {
	if rt.Kind() == reflect.Ptr {
		rt = rt.Elem()
	}
	if rt.Kind() != reflect.Struct {
		panic("must be struct type")
	}

	titles := make([]string, 0)
	title2FieldNameMap := make(map[string]string)
	for i := 0; i < rt.NumField(); i++ {
		field := rt.Field(i)
		if title, ok := field.Tag.Lookup(titleTag); ok {
			titles = append(titles, title)
			if _, ok := title2FieldNameMap[title]; ok {
				panic("excelTitle名称重复")
			}
			title2FieldNameMap[title] = field.Name
		}
	}
	return titles, title2FieldNameMap
}
